/**
 * 优化的iframe通信工具
 * 提供类型安全、错误处理、消息确认等功能
 */

export interface MessagePayload<T = any> {
  id: string;
  method: string;
  data?: T;
  timestamp: number;
  source: 'Vue' | 'ThingJS';
  type?: 'request' | 'response' | 'notification';
  responseId?: string; // 响应消息的原始消息ID
  success?: boolean;
  error?: string;
}

export interface MessageOptions {
  timeout?: number; // 响应超时时间(ms)
  retry?: number; // 重试次数
  expectResponse?: boolean; // 是否期待响应
}

export class IframeMessenger {
  private iframe: HTMLIFrameElement | null = null;
  private origin: string = '*'; // 建议设置为具体的域名
  private pendingRequests = new Map<
    string,
    {
      resolve: (value: any) => void;
      reject: (reason: any) => void;
      timer: NodeJS.Timeout;
      retryCount: number;
      maxRetries: number;
    }
  >();
  private messageHandlers = new Map<string, (data: any, message: MessagePayload) => void>();
  private messageListener: ((event: MessageEvent) => void) | null = null;

  constructor(iframe?: HTMLIFrameElement, origin?: string) {
    this.iframe = iframe || null;
    this.origin = origin || '*';
    this.setupMessageListener();
  }

  /**
   * 设置iframe实例
   */
  setIframe(iframe: HTMLIFrameElement) {
    this.iframe = iframe;
  }

  /**
   * 设置安全的目标域名
   */
  setOrigin(origin: string) {
    this.origin = origin;
  }

  /**
   * 发送消息（带响应确认）
   */
  async sendMessage<T = any>(method: string, data?: any, options: MessageOptions = {}): Promise<T> {
    if (!this.iframe?.contentWindow) {
      throw new Error('iframe未准备好');
    }

    const { timeout = 5000, retry = 2, expectResponse = true } = options;
    const messageId = this.generateMessageId();

    const message: MessagePayload = {
      id: messageId,
      method,
      data,
      timestamp: Date.now(),
      source: 'Vue',
      type: expectResponse ? 'request' : 'notification'
    };

    if (!expectResponse) {
      // 不需要响应的通知消息
      this.postMessage(message);
      return Promise.resolve(null as T);
    }

    // 需要响应的请求消息
    return new Promise<T>((resolve, reject) => {
      const timer = setTimeout(() => {
        const pending = this.pendingRequests.get(messageId);
        if (pending && pending.retryCount < pending.maxRetries) {
          // 重试
          pending.retryCount++;
          console.warn(`消息重试 ${pending.retryCount}/${pending.maxRetries}:`, method);
          this.postMessage(message);

          // 重新设置超时
          clearTimeout(pending.timer);
          pending.timer = setTimeout(() => {
            this.pendingRequests.delete(messageId);
            reject(new Error(`消息超时: ${method}`));
          }, timeout);
        } else {
          this.pendingRequests.delete(messageId);
          reject(new Error(`消息超时: ${method}`));
        }
      }, timeout);

      this.pendingRequests.set(messageId, {
        resolve,
        reject,
        timer,
        retryCount: 0,
        maxRetries: retry
      });

      this.postMessage(message);
    });
  }

  /**
   * 发送通知消息（不需要响应）
   */
  notify(method: string, data?: any): void {
    this.sendMessage(method, data, { expectResponse: false });
  }

  /**
   * 注册消息处理器
   */
  onMessage<T = any>(method: string, handler: (data: T, message: MessagePayload) => void | Promise<any>) {
    this.messageHandlers.set(method, handler);
  }

  /**
   * 移除消息处理器
   */
  offMessage(method: string) {
    this.messageHandlers.delete(method);
  }

  /**
   * 响应消息
   */
  private respond(originalMessage: MessagePayload, data?: any, success: boolean = true, error?: string) {
    if (!this.iframe?.contentWindow) return;

    const response: MessagePayload = {
      id: this.generateMessageId(),
      method: originalMessage.method,
      data,
      timestamp: Date.now(),
      source: 'Vue',
      type: 'response',
      responseId: originalMessage.id,
      success,
      error
    };

    this.postMessage(response);
  }

  /**
   * 批量发送消息（性能优化）
   */
  async batchSend(messages: Array<{ method: string; data?: any; options?: MessageOptions }>): Promise<any[]> {
    const promises = messages.map(({ method, data, options }) => this.sendMessage(method, data, options).catch((err) => ({ error: err.message })));

    return Promise.all(promises);
  }

  /**
   * 节流发送（防止频繁发送相同类型的消息）
   */
  private throttleTimers = new Map<string, NodeJS.Timeout>();

  throttledSend(method: string, data?: any, delay: number = 16): void {
    if (this.throttleTimers.has(method)) {
      clearTimeout(this.throttleTimers.get(method)!);
    }

    const timer = setTimeout(() => {
      this.notify(method, data);
      this.throttleTimers.delete(method);
    }, delay);

    this.throttleTimers.set(method, timer);
  }

  /**
   * 设置消息监听器
   */
  private setupMessageListener() {
    this.messageListener = (event: MessageEvent) => {
      try {
        const message: MessagePayload = event.data;

        if (!message || !message.method) return;

        // 验证消息来源
        if (message.source === 'Vue') return; // 忽略自己发送的消息

        // 确保消息来自我们的iframe
        if (this.iframe && event.source !== this.iframe.contentWindow) {
          return; // 忽略来自其他iframe的消息
        }

        console.log('📥 收到ThingJS消息:', message);

        if (message.type === 'response') {
          // 处理响应消息
          this.handleResponse(message);
        } else {
          // 处理请求/通知消息
          this.handleRequest(message);
        }
      } catch (error) {
        console.error('处理消息失败:', error);
      }
    };

    window.addEventListener('message', this.messageListener);
  }

  /**
   * 处理响应消息
   */
  private handleResponse(message: MessagePayload) {
    if (!message.responseId) return;

    const pending = this.pendingRequests.get(message.responseId);
    if (pending) {
      clearTimeout(pending.timer);
      this.pendingRequests.delete(message.responseId);

      if (message.success) {
        pending.resolve(message.data);
      } else {
        pending.reject(new Error(message.error || '未知错误'));
      }
    }
  }

  /**
   * 处理请求/通知消息
   */
  private async handleRequest(message: MessagePayload) {
    const handler = this.messageHandlers.get(message.method);

    if (handler) {
      try {
        const result = await handler(message.data, message);

        // 如果是请求消息，发送响应
        if (message.type === 'request') {
          this.respond(message, result, true);
        }
      } catch (error) {
        console.error(`处理消息 ${message.method} 失败:`, error);

        // 如果是请求消息，发送错误响应
        if (message.type === 'request') {
          this.respond(message, null, false, error instanceof Error ? error.message : '处理失败');
        }
      }
    } else {
      console.warn(`未找到消息处理器: ${message.method}`);

      // 如果是请求消息，发送未找到处理器的响应
      if (message.type === 'request') {
        this.respond(message, null, false, `未找到处理器: ${message.method}`);
      }
    }
  }

  /**
   * 清理数据，确保可以被postMessage传递
   */
  private sanitizeData(data: any): any {
    try {
      // 使用JSON序列化/反序列化来清理数据，移除不可克隆的对象
      return JSON.parse(JSON.stringify(data));
    } catch (error) {
      console.warn('数据序列化失败，使用空对象:', error, data);
      return {};
    }
  }

  /**
   * 发送消息到iframe
   */
  private postMessage(message: MessagePayload) {
    if (!this.iframe || !this.iframe.contentWindow) {
      console.warn('iframe不可用，跳过消息发送:', message.method);
      return;
    }

    // 检查iframe是否仍然在DOM中
    if (!document.body.contains(this.iframe)) {
      console.warn('iframe已从DOM中移除，跳过消息发送:', message.method);
      this.iframe = null; // 清理引用
      return;
    }

    try {
      // 清理消息数据，确保可以被postMessage传递
      const sanitizedMessage = {
        ...message,
        data: this.sanitizeData(message.data)
      };

      this.iframe.contentWindow.postMessage(sanitizedMessage, this.origin);
    } catch (error) {
      console.error('发送消息失败:', error);

      // 如果是DataCloneError，尝试进一步清理数据
      if (error instanceof Error && error.name === 'DataCloneError') {
        console.warn('检测到DataCloneError，尝试发送简化的消息');
        try {
          const fallbackMessage = {
            method: message.method,
            id: message.id,
            source: message.source,
            data: typeof message.data === 'object' ? {} : String(message.data),
            timestamp: message.timestamp
          };
          this.iframe.contentWindow.postMessage(fallbackMessage, this.origin);
        } catch (fallbackError) {
          console.error('发送简化消息也失败:', fallbackError);
        }
      } else if (error instanceof Error && error.message.includes('null')) {
        this.iframe = null; // 清理引用
      }
    }
  }

  /**
   * 生成唯一消息ID
   */
  private generateMessageId(): string {
    return `vue_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }

  /**
   * 销毁实例
   */
  destroy() {
    if (this.messageListener) {
      window.removeEventListener('message', this.messageListener);
      this.messageListener = null;
    }

    // 清理所有待处理的请求
    this.pendingRequests.forEach((pending) => {
      clearTimeout(pending.timer);
      pending.reject(new Error('Messenger已销毁'));
    });
    this.pendingRequests.clear();

    // 清理节流定时器
    this.throttleTimers.forEach((timer) => clearTimeout(timer));
    this.throttleTimers.clear();

    this.messageHandlers.clear();
  }
}

// 导出单例实例
export const iframeMessenger = new IframeMessenger();
